/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package steg.sekret;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import steg.steki.StegException;
import steg.steki.bmp.PlikBMP;
import steg.steki.wav.PlikWAV;
import steg.utils.SkrotSha1;

/**
 *  Klasa reprezentująca plik posiadający(potencjalnie) ukrytą wiadomość.
 *  Oraz zawierające dane do jej odzyskania. 
 *
 *
 * @author 
 */
public class UnSekret {

// ------------------------------- ZIENNE PRYWATNE -----------------------------
    //-- stałe
    //-- czy
    //private boolean czySekretAsText = false;   -- bez sensu, do pliku a w GUI decyzja co zrobić z danymi.
    private boolean czyZnacznik = false;
    private boolean czyHaslo = false;

    private boolean czyAllKanaly = true;
    private boolean czyOdPoczatku = true;
    private boolean czyReverse = false;
    private boolean czyWyrownaj = false;
    private boolean czyZip = false;
       
    //-- zmienne
    private File skPlik;
    private String extencion;
    private String skWiadomosc;

    private byte[] sekretHaslo;
    private int skBitowNaSample;
    private int skKanal;


    private long pozWiadomosci = 0;

// ------------------------------- ZIENNE PUBLICZNE
    //-- czy
    //-- zmienne

// ------------------------------- KONSTRUKTORY
    public UnSekret() {
    }

    public UnSekret(File file) {
        skPlik = file;
    }

// ******************************** PUBLICZNE **********************************
// *****************************************************************************
// ------------------------------- FUNKCJE KRYTYCZNE ---------------------------
    /**
     * Funkcja unsteg, w zależności od paramterów wyszuka i jeśli to możliwe
     * odczyta ukrytą wiadomość w pliku !    
     *
     * @param b
     */
    @Deprecated
    public void unsteg(PlikBMP bmp) throws StegException, IOException {

        try {

            //2. otworz odczyt/zapis, bo jak belad to po co wpisywac
            OutputStream out = new FileOutputStream( bmp.getFile() );
            DataOutputStream dataOut = new DataOutputStream(out);

            InputStream in = new FileInputStream( this.getFile() );
            DataInputStream dataIn = new DataInputStream(in);

            //3 przeskocz nagowek
            int licznik = bmp.getBfOffBits();
            dataIn.skipBytes(licznik);

            //4 wczytaj dane
            byte bSteg,bInfo=0;
            int bns = this.getSkBitowNaSample();

            // stworz maske
            byte maska = (byte) 0x7F;
            if(bns!=8)
                maska >>= 7-bns;
            else
                maska = (byte) 0xFF;

            int licznikBitow = 8-bns;


            while( /*in.available() !=0 &&*/ licznik++<bmp.getBfSize() ) {

                // reset przesumiecia
                if(licznikBitow<0) {
                    licznikBitow = 8-bns;
                    dataOut.writeByte( bInfo );
                    bInfo=0;
                }

                //pobranie bitow
                bSteg = dataIn.readByte();
                bSteg &= maska;

                //przesuniecie pobranych bitow
                bSteg <<= licznikBitow;

                //uzulelnienie informacji
                bInfo |=bSteg;

                licznikBitow-=bns;


                //dataOut.write( bSteg );



            }

            dataOut.close();
            dataIn.close();


        }catch(EOFException eofe) {
            //jak sie zdarzy
            throw new StegException(eofe, StegException.BLAD_ZLY_FORMAT_PLIKU, "");

        }

    }
    @Deprecated
    public void unsteg(PlikWAV wav) throws StegException, IOException {

        try {

            //1. otworz odczyt/zapis
            // plik wav a więc wzor+info
            InputStream in = new FileInputStream( wav.getFile() );
            DataInputStream dataIn = new DataInputStream(in);

            // plik do ktorego zostanie wypluta informacja
            OutputStream out = new FileOutputStream( this.getFile() );
            DataOutputStream dataOut = new DataOutputStream(out);

            //2 przeskocz nagowek
            int licznik = 12 + wav.getFMTlenght() + 4; // 12 header, FMT, 4 "data";
            dataIn.skipBytes(licznik);

            //3. dlugosc pliku
            licznik = Integer.reverseBytes(dataIn.readInt() );


            // -- ALGORYTM --

            //zmienne algorytmu
            byte bSteg,bInfo=0;
            int bns = this.getSkBitowNaSample();

            //4. stworz maske
            byte maska = (byte) 0x7F;
            if(bns!=8)
                maska >>= 7-bns;
            else
                maska = (byte) 0xFF;


            int licznikBitow = 8-bns;

            //5. wczytywanie, w przypadku EOT, wyżuci wyjątek
            while(--licznik>0 ) {

                // reset przesumiecia
                if(licznikBitow<0) {
                    licznikBitow = 8-bns;
                    dataOut.writeByte( bInfo );
                    bInfo=0;
                }

                //pobranie bitow
                bSteg = dataIn.readByte();
                bSteg &= maska;

                //przesuniecie pobranych bitow
                bSteg <<= licznikBitow;

                //uzulelnienie informacji
                bInfo |=bSteg;

                licznikBitow-=bns;


                //dataOut.write( bSteg );



            }

            dataOut.close();
            dataIn.close();


        }catch(EOFException eofe) {
            //jak sie zdarzy
            throw new StegException(eofe, StegException.BLAD_ZLY_FORMAT_PLIKU, "");

        }

    }

// ------------------------------- FUNKCJE DODATKOWE ---------------------------
    public static boolean parseSekretTag(SekretInfo sinfo, byte[] bity) {

        if(bity.length!=13) return false; // znacznik ma 13 bitów
        
                // konstrukcja znacznika tagu
                // 4 byte to TAG
                // 1 kolejny to
                //      - 1 bit, pusty 0, coś funkcja radix bez tego miesza :/
                //      - 2 bit, czy text 1 is true
                //      - 3 bit, czy haslo 1 is true
                //      - 4 bit, czy zip 1 is true
                //      - 5,6,7,8 bit, ile na sample <1,8>
                //
                // 8 byte to dl pliku

                // = 13 bytów

        if( !(bity[0]==Sekret.ZNACZNIK[0] &&
              bity[1]==Sekret.ZNACZNIK[1] &&
              bity[2]==Sekret.ZNACZNIK[2] &&
              bity[3]==Sekret.ZNACZNIK[3] ) ) return false; // czy to znacznik

        
        // flagi
        int srBicik = bity[4];
        int temp = 0;
        boolean tempIs = false;

        // 1 bit
        temp = srBicik >> 7;

        //powinno byc zawsze 0!
        if(temp!=0) return false;
        sinfo.setTag(true);

        // 2 bit
        temp = srBicik >> 6;
        tempIs = temp!=0 ? true : false;
        sinfo.setSekretAsText( tempIs );

        // 3 bit
        temp = srBicik >> 5;
        tempIs = temp!=0 ? true : false;
        sinfo.setIsHaslo( tempIs );

        //4 bit
        temp = srBicik >> 4;
        tempIs = temp!=0 ? true : false;
        sinfo.setZip( tempIs );



        //dlgufosc
        long l = 0;
        // array to long
        for(int i =5; i < bity.length; i++){
            l <<= 8;
            l ^= (long)bity[i] & 0xFF;
        }
        l = Long.reverseBytes(l);

        sinfo.setLength( l);
        
        return true;
    }


// ------------------------------- FUNKCJE dziwne ------------------------------



// ******************************** PRYWATNE ***********************************
// *****************************************************************************
// ------------------------------- FUNKCJE KRYTYCZNE


// ------------------------------- FUNKCJE POMOCNICZE

    public boolean isAllKanaly() {
        return czyAllKanaly;
    }

    public void setCzyAllKanaly(boolean czyAllKanaly) {
        this.czyAllKanaly = czyAllKanaly;throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isOdPoczatku() {
        return czyOdPoczatku;
    }

    public void setCzyOdPoczatku(boolean czyOdPoczatku) {
        this.czyOdPoczatku = czyOdPoczatku;throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isReverse() {
        return czyReverse;
    }

    public void setCzyReverse(boolean czyReverse) {
        this.czyReverse = czyReverse;throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isWyrownaj() {
        return czyWyrownaj;
    }

    public void setCzyWyrownaj(boolean czyWyrownaj) {
        this.czyWyrownaj = czyWyrownaj;throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isGZip() {
        return czyZip;
    }

    public void setCzyGZip(boolean czyZip) {
        this.czyZip = czyZip;throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isZnacznik() {
        return czyZnacznik;
    }

    public void setCzyZnacznik(boolean czyZnacznik) {
        this.czyZnacznik = czyZnacznik;
    }

    public String getExtencion() {
        return extencion;
    }

    public void setExtencion(String extencion) {
        this.extencion = extencion;throw new UnsupportedOperationException("Not supported yet.");
    }

    public long getPozWiadomosci() {
        return pozWiadomosci;
    }

    public void setPozWiadomosci(long pozWiadomosci) {
        this.pozWiadomosci = pozWiadomosci;throw new UnsupportedOperationException("Not supported yet.");
    }

    public int getSkBitowNaSample() {
        return skBitowNaSample;
    }

    /**
     * Ilość bitów w samplu danych np. kolor R w palecie RGB
     * które zostaną nadpisane tajną wiadomością.
     *
     * @param skBitowNaSample
     */
    public void setBitowNaSample(int skBitowNaSample) {
        this.skBitowNaSample = skBitowNaSample;
    }

    public byte[] getSkHaslo() {
        return sekretHaslo;
    }

    public void setSekretHaslo(byte[] sekretHaslo) {
        this.sekretHaslo = sekretHaslo;
    }

    public void setSekretHaslo(char[] sHch ) throws StegException {

        // to bedzie klamac ale w dupie z tym
          // tworzenie chasła

        byte[] tempbyte = new byte[sHch.length]; // 4 integer czyli lendoklejony do hasla na poczatku
        int i=0;
        for (char elem : sHch) {
            tempbyte[i++] = (byte)elem;
        }

        this.sekretHaslo = tempbyte;
        sHch = new char[0]; //haslo char, zgodnie z zaleceniem kasujemy

        // haszujemymy
        try{

        // tworzenie chasła
            sekretHaslo = SkrotSha1.SHA1( new String(sekretHaslo) );

        } catch (NoSuchAlgorithmException ex) {
            throw new StegException( ex, StegException.BLAD_INNY, "Bład skrótu SHA-1!" );
        } catch (UnsupportedEncodingException ex) {
            throw new StegException( ex, StegException.BLAD_INNY, "Bład skrótu tworzenia SHA-1!" );
        }


    }

    public boolean isCzyHaslo() {
        return czyHaslo;
    }

    public void setCzyHaslo(boolean czyHaslo) {
        this.czyHaslo = czyHaslo;
    }
    


    public int getSkKanal() {
        return skKanal;
    }

    public void setKanal(int skKanal) {
        this.skKanal = skKanal;throw new UnsupportedOperationException("Not supported yet.");
    }

    public File getFile() {
        return skPlik;
    }

    public void setPlik(File skPlik) {
        this.skPlik = skPlik;throw new UnsupportedOperationException("Not supported yet.");
    }

    public String getWiadomosc() {
        return skWiadomosc;
    }

    public void setWiadomosc(String skWiadomosc) {
        this.skWiadomosc = skWiadomosc;throw new UnsupportedOperationException("Not supported yet.");
    }



}
